﻿#include "ImageCommon.h"
#include <QImage>
#include <QPixmap>
#include <QWidget>
#include <QLabel>
#ifdef USE_HALCON
using namespace HalconCpp;
#endif


bool rgb2bgr( unsigned char* pRgbData, unsigned int nWidth, unsigned int nHeight )
{
    if (NULL == pRgbData){
        return false;
    }

    for (unsigned int j = 0; j < nHeight; j++){
        for (unsigned int i = 0; i < nWidth; i++){
            unsigned char red = pRgbData[j * (nWidth * 3) + i * 3];
            pRgbData[j * (nWidth * 3) + i * 3]     = pRgbData[j * (nWidth * 3) + i * 3 + 2];
            pRgbData[j * (nWidth * 3) + i * 3 + 2] = red;
        }
    }

    return 0;
}

#ifdef USE_OPENCV
cv::Mat ImageCommon::imageToMat(const QImage &image)
{
    cv::Mat mat;
    switch (image.format())  //QImage 的一个库函数 可以返回图片的类型
    {
    case QImage::Format_RGB32:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.bits(), image.bytesPerLine());
        cv::cvtColor(mat,mat,cv::COLOR_BGRA2BGR);   //转3通道
        break;
    case QImage::Format_ARGB32_Premultiplied:  //RGB32 为四通道的所以在调用mat构造函数需要转换成四通道的mat类型（CV_8UC4）
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.bits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:   //RGB888 即RGB24 三通道八位的图片 所以转成三通道的mat(CV_8UC4)
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.bits(), image.bytesPerLine());
        //因为Qimage 是RGB 通道 而 Mat 为 BGR 通道 所以需要使用cvtcolor进行转换，不然图片通道会颠倒
        cv::cvtColor(mat, mat,cv::COLOR_RGB2BGR);
        break;
    case QImage::Format_Grayscale8:
    case QImage::Format_Indexed8:  //Indexed8 为单通道的图片 所以在转换成mat 也是单通道（CV_8UC1）
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.bits(), image.bytesPerLine());
        break;
    default:
        break;
    }
    return mat;
}
QImage ImageCommon::matToImage(const cv::Mat &mat)
{
    QImage img;
    switch ( mat.type() )
    {
    // 8-bit, 4 channel
    case CV_8UC4:
        img = QImage( mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB32 );
        break;
        // 8-bit, 3 channel
    case CV_8UC3:
        img = QImage( mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888 );
        break;
        // 8-bit, 1 channel
    case CV_8UC1:
        static QVector<QRgb>  sColorTable;
        // only create our color table once
        if (sColorTable.isEmpty() ){
            for ( int i = 0; i < 256; ++i )
                sColorTable.push_back( qRgb( i, i, i ) );
        }
        img = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8 );
        img.setColorTable( sColorTable );
        break;
    // default:
    //     qDebug("Image format is not supported: depth=%d and %d channels\n", mat.depth(), mat.channels());
    //     break;
    }
    return img;
}
QPixmap ImageCommon::matToPixmap(const cv::Mat &mat)
{
    QImage img = matToImage(mat);;
    QPixmap pixmap = QPixmap::fromImage(img);
    return pixmap;
}
cv::Mat unsignchar2Mat(int height,int width,int channel, unsigned char * pData)
{
    cv::Mat srcImage;
    if(channel == 1){
        srcImage = cv::Mat(height, width, CV_8UC1, pData);
    }else if(channel == 3){
        rgb2bgr(pData, width, height);
        srcImage = cv::Mat(height, width, CV_8UC3, pData);
    }else{
        return srcImage;
    }
    if (NULL == srcImage.data){
        return srcImage;
    }
    return srcImage;
}
void showImage(cv::Mat image, QWidget* widget)
{
    QImage qimage = ImageCommon::matToImage(image);
    QPixmap image1=QPixmap::fromImage(qimage);//重新调整图像大小以适应窗口
    widget->setAutoFillBackground(true); // 这句要加上, 否则可能显示不出背景图.
    QPalette palette = widget->palette();
    palette.setBrush(QPalette::Window,
                     QBrush(image1.scaled(widget->size(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation))); // 使用平滑的缩放方式
    widget->setPalette(palette); // 至此, 已给widget加上了背景图.
}

void showImage(cv::Mat image, QLabel *lbl)
{
    QImage qimage = ImageCommon::matToImage(image);
    QPixmap image1 = QPixmap::fromImage(qimage);
    QPixmap image2 = image1.scaled(lbl->size()-QSize(2,2),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);//重新调整图像大小以适应窗口
    lbl->setPixmap(image2);
}
#endif
#if((defined USE_OPENCV) && (defined USE_HALCON))
HalconCpp::HObject ImageCommon::matToHImage(cv::Mat &cv_img)
{
    HalconCpp::HObject himg;
    if (cv_img.channels() == 1){
        int height = cv_img.rows, width = cv_img.cols;
        int size = height * width;
        uchar* temp = new uchar[size];

        memcpy(temp, cv_img.data, size);
        HalconCpp::GenImage1(&himg, "byte", width, height, (Hlong)(temp));

        delete[] temp;
    }else if (cv_img.channels() == 3){
        int height = cv_img.rows, width = cv_img.cols;
        int size = height * width;
        uchar* B = new uchar[size];
        uchar* G = new uchar[size];
        uchar* R = new uchar[size];

        for (int i = 0; i < height; i++){
            unsigned char* p = cv_img.ptr<unsigned char>(i);
            for (int j = 0; j < width; j++){
                B[i * width + j] = p[3 * j];
                G[i * width + j] = p[3 * j + 1];
                R[i * width + j] = p[3 * j + 2];
            }
        }
        HalconCpp::GenImage3(&himg, "byte", width, height, (Hlong)(R), (Hlong)(G), (Hlong)(B));

        delete[] R;
        delete[] G;
        delete[] B;
    }
    return himg;
}

cv::Mat ImageCommon::hImageToMat(const HObject& hobj)
{
    cv::Mat mat;
    HTuple htCh = HTuple();
    HTuple cType;
    HImage himg;
    ConvertImageType(hobj, &himg, "byte");
    CountChannels(himg, &htCh);
    HTuple wid;
    HTuple hgt;
    int W, H;
    if (htCh[0].I() == 1){
        HTuple ptr;
        GetImagePointer1(himg, &ptr, &cType, &wid, &hgt);
        W = (Hlong)wid;
        H = (Hlong)hgt;
        mat.create(H, W, CV_8UC1);
        uchar* pdata = (uchar*)ptr[0].L();
        memcpy(mat.data, pdata, W*H);
    }else if (htCh[0].I() == 3){
        HTuple ptrR, ptrG, ptrB;
        GetImagePointer3(himg, &ptrR, &ptrG, &ptrB, &cType, &wid, &hgt);
        W = (Hlong)wid;
        H = (Hlong)hgt;
        mat.create(H, W, CV_8UC3);
        std::vector<cv::Mat> vecM(3);
        vecM[2].create(H, W, CV_8UC1);
        vecM[1].create(H, W, CV_8UC1);
        vecM[0].create(H, W, CV_8UC1);
        uchar* pr = (uchar*)ptrR[0].L();
        uchar* pg = (uchar*)ptrG[0].L();
        uchar* pb = (uchar*)ptrB[0].L();
        memcpy(vecM[2].data, pr, W*H);
        memcpy(vecM[1].data, pg, W*H);
        memcpy(vecM[0].data, pb, W*H);
        merge(vecM, mat);
    }
    return mat;

}
#endif

#ifdef USE_HALCON
HalconCpp::HObject hobjectFromBuffer(int nWidth, int nHeight,unsigned char *pbuffer, HTuple type)
{
    HImage hi_image;
    if (type=="mono"){
        hi_image.GenImage1("byte",  nWidth, nHeight,(void*)pbuffer);
    }else if(type=="bgr"){
        hi_image.GenImageInterleaved((void*)pbuffer, "bgr", nWidth, nHeight, 0,  "byte", nWidth, nHeight, 0, 0, 8, 0);
    }else if (type=="rgb"){
        hi_image.GenImageInterleaved((void*)pbuffer, "rgb", nWidth, nHeight, 0,  "byte", nWidth, nHeight, 0, 0, 8, 0);
    }else if (type=="bgrx"){
        hi_image.GenImageInterleaved((void*)pbuffer, "bgrx", nWidth, nHeight, 0,  "byte", nWidth, nHeight, 0, 0, 8, 0);
    }else if (type=="rgbx"){
        hi_image.GenImageInterleaved((void*)pbuffer, "rgbx", nWidth, nHeight, 0,  "byte", nWidth, nHeight, 0, 0, 8, 0);
    }
    return hi_image;
}
HalconCpp::HObject ImageCommon::imageToHImage(const QImage &from)
{
    HImage image;
    GenEmptyObj(&image);
    if(from.isNull())
        return image;
    int width = from.width(), height = from.height();
    QImage::Format format = from.format();

    if(format == QImage::Format_RGB32 ||
        format == QImage::Format_ARGB32 ||
        format == QImage::Format_ARGB32_Premultiplied){
        image.GenImageInterleaved((void*)from.bits(), "rgbx", width, height, 0,  "byte", width, height, 0, 0, 8, 0);
    }else if(format == QImage::Format_RGB888){
        image.GenImageInterleaved((void*)from.bits(), "rgb", width, height, 0,  "byte", width, height, 0, 0, 8, 0);
    }else if(format == QImage::Format_BGR30){
        image.GenImageInterleaved((void*)from.bits(), "bgr", width, height, 0,  "byte", width, height, 0, 0, 8, 0);
    }else if(format == QImage::Format_Grayscale8 || format == QImage::Format_Indexed8){
        image.GenImage1("byte", width, height, (void*)from.bits());
    }
    return image;
}

QImage ImageCommon::hImageToImage(const HalconCpp::HObject &from)
{
    QImage to;
    Hlong width;
    Hlong height;
    HImage image;
    ConvertImageType(from, &image, "byte");
    image.GetImageSize(&width, &height);

    HTuple channels = image.CountChannels();
    HTuple type = image.GetImageType();

    if( strcmp(type[0].S(), "byte")){
        return to;
    }

    QImage::Format format;
    switch(channels[0].I()){
    case 1:
        format = QImage::Format_Grayscale8;
        break;
    case 3:
        format = QImage::Format_RGB32;
        break;
    default:
        return to;
    }

    if(to.width() != width || to.height() != height || to.format() != format){
        to = QImage(static_cast<int>(width),static_cast<int>(height),format);
    }
    HString Type;
    if(channels[0].I() == 1){
        unsigned char * pSrc = reinterpret_cast<unsigned char *>( image.GetImagePointer1(&Type, &width, &height) );
        memcpy( to.bits(), pSrc, static_cast<size_t>(width) * static_cast<size_t>(height));
    }else if(channels[0].I() == 3){
        uchar *R, *G, *B;
        image.GetImagePointer3(reinterpret_cast<void **>(&R),
                               reinterpret_cast<void **>(&G),
                               reinterpret_cast<void **>(&B), &Type, &width, &height);
        for(int row = 0; row < height; row ++){
            QRgb* line = reinterpret_cast<QRgb*>(to.scanLine(row));
            for(int col = 0; col < width; col ++){
                line[col] = qRgb(*R++, *G++, *B++);
            }
        }
    }
    return to;

}
#endif







